package com.zzu.base.filter;

import com.zzu.base.common.pojo.LoginUser;
import com.zzu.base.common.utils.JwtUtil;
import com.zzu.base.handler.AuthenticationExceptionHandler;
import io.jsonwebtoken.Claims;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.net.ProtocolException;

@Component
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Resource
    private UserDetailsService userDetailsService;
    @Resource
    private RedisTemplate<String,Object> redisTemplate;
    @Resource
    private AuthenticationExceptionHandler authenticationExceptionHandler;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        // 获取token
        String token = request.getHeader("token");
        AuthenticationException authException = null;
        // 记录请求日志
        log.debug("处理请求: {} {}", request.getMethod(), request.getRequestURI());

        if (!StringUtils.hasText(token)) {
            log.debug("请求未携带Token，放行");
            filterChain.doFilter(request, response);
            return;
        }

        try {
            boolean isBlacklisted= Boolean.TRUE.equals(redisTemplate.hasKey("not_used" + token));
            if (isBlacklisted) {
                log.warn("Token已失效，请求路径: {}", request.getRequestURI());
                authException= new BadCredentialsException("Token已失效,请重新登录");
            }
            // 解析Token
            Claims claims = JwtUtil.parseJWT(token);

            // 检查Token有效期
            if (JwtUtil.isTokenExpired(claims)) {
                log.warn("Token已过期，请求路径: {}", request.getRequestURI());
                authException= new CredentialsExpiredException("Token已过期");
            }

            // 获取用户名并加载用户信息
            String username = JwtUtil.getUserName(claims);
            LoginUser loginUser = (LoginUser) userDetailsService.loadUserByUsername(username);

            // 检查Token是否需要刷新（但仍有效）
            if (JwtUtil.isTokenNeedRefresh(claims)) {
                log.info("Token需要刷新，用户: {}", username);
                // 可以在这里生成新Token并添加到响应头
                String newToken = JwtUtil.createJWT(
                        loginUser.getUsername(),
                        loginUser.getRoles(),
                        loginUser.getPermissions()
                );
                response.setHeader("new-token", newToken);
            }

            // 设置认证信息到SecurityContext
            UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
                    loginUser, null, loginUser.getAuthorities()
            );
            SecurityContextHolder.getContext().setAuthentication(auth);
            log.debug("用户 {} 认证成功", username);

        } catch (Exception e) {
            log.error("JWT认证失败，请求路径: {}, 错误: {}",
                    request.getRequestURI(), e.getMessage());
            authException= new BadCredentialsException("JWT认证失败");
        }
        if (authException != null) {
            authenticationExceptionHandler.commence(request, response, authException);
            return;
        }
        // 继续过滤链
        filterChain.doFilter(request, response);
    }
}
